package xyz.jcat.auth.token;

import xyz.jcat.common.util.CodeUtils;
import xyz.jcat.common.util.StringUtils;
import xyz.jcat.common.web.RespCodeMsg;
import xyz.jcat.common.web.RespException;
import xyz.jcat.redis.RedisUtils;

import java.text.MessageFormat;
import java.util.Optional;

public class AccessTokenUtils {

    private static final String TOKEN_HEAD = "Bearer ";
    private static final int TOKEN_HEAD_LEN = 7;
    public static final String TOKEN_HEADER = "Authorization";

    private static final String REDIS_KEY_TOKEN_USER = "token:{0}:user";
    private static final String REDIS_KEY_USERID_TOKEN = "user:{0}:token";

    public static String getHeaderAccessToken(String requestHeaderToken) {
        if(StringUtils.isNotEmpty(requestHeaderToken) && requestHeaderToken.startsWith(TOKEN_HEAD)) {
            return requestHeaderToken.substring(TOKEN_HEAD_LEN);
        }
        return null;
    }

    public static void removeAccessToken(Long userId, String accessToken) {
        RedisUtils.del(getAccessTokenUserKey(accessToken));
        RedisUtils.del(getUserIdTokenKey(userId));
    }

    public static UserTokenDto getUserToken(String accessToken) {
        if(StringUtils.isBlank(accessToken)) {
            throw new RespException(RespCodeMsg.INVALID_TOKEN);
        }
        Optional<UserTokenDto> userTokenOpt = RedisUtils.get(getAccessTokenUserKey(accessToken), UserTokenDto.class);
        if(userTokenOpt.isPresent()) {
            return userTokenOpt.get();
        }
        throw new RespException(RespCodeMsg.TOKEN_EXPIRED);
    }

    public static String generateAccessToken(UserTokenDto userToken, long timeout) {
        String accessToken = CodeUtils.genAccessTokenByUUID();
        RedisUtils.set(getAccessTokenUserKey(accessToken), userToken, timeout);
        RedisUtils.set(getUserIdTokenKey(userToken.getId()), accessToken, timeout);
        return accessToken;
    }

    private static String getAccessTokenUserKey(String accessToken) {
        return MessageFormat.format(REDIS_KEY_TOKEN_USER, accessToken);
    }

    private static String getUserIdTokenKey(Long userId) {
        return MessageFormat.format(REDIS_KEY_USERID_TOKEN, userId);
    }

    public static void updateUserToken(UserTokenDto userToken) {
        Optional<String> tokenOpt = getAccessToken(userToken.getId());
        if(!tokenOpt.isPresent())
            return;
        String accessTokenUserKey = getAccessTokenUserKey(tokenOpt.get());
        long expire = RedisUtils.getExpire(accessTokenUserKey);
        RedisUtils.set(accessTokenUserKey, userToken, expire);
    }

    private static Optional<String> getAccessToken(Long userId) {
        String userIdTokenKey = getUserIdTokenKey(userId);
        return RedisUtils.get(userIdTokenKey);
    }

    public static void removeAccessToken(Long userId) {
        Optional<String> tokenOpt = getAccessToken(userId);
        if(!tokenOpt.isPresent())
            return;
        removeAccessToken(userId, tokenOpt.get());
    }
}
